#include "soft_i2c.h"
#include "delay.h"

uint8_t BSP_SoftI2C_Send7BitAddress(Device_SoftI2C dv, uint8_t addr, uint8_t rwBit, uint8_t inIrq){
    uint8_t data = addr << 1;
    data = data | (0x01&rwBit);
    return BSP_SoftI2C_SendByte(dv, data, inIrq);
}

uint8_t BSP_SoftI2C_SendByte(Device_SoftI2C dv, uint8_t data, uint8_t inIrq){
    uint8_t msk, t;
    for(msk = 0x80; msk >= 0x01; msk = msk>>1){
        t = data & msk;
        if(t == 0x00){
            BSP_SoftI2C_SendBit(dv, Bit_RESET, inIrq);
        }else{
            BSP_SoftI2C_SendBit(dv, Bit_SET, inIrq);
        }
    }

    uint8_t ret = BSP_SoftI2C_ReceiveBit(dv, inIrq);
    return ret;
}

uint8_t BSP_SoftI2C_ReceiveByte(Device_SoftI2C dv, uint8_t inIrq, uint8_t* err){
    *err = 0;
    uint8_t t, msk, data;
    data = 0x00;
    for(msk = 0x80; msk >= 0x01; msk = msk>>1){
        t = BSP_SoftI2C_ReceiveBit(dv, inIrq);
        if(t == 1U){
            data = data | msk;
        }else if(t == 2U){
            *err = 1;
            BSP_SoftI2C_SendBit(dv, Bit_SET, inIrq);
            return data;
        }else{
            continue;
        }
    }
    return data;
}

void BSP_SoftI2C_SendBit(Device_SoftI2C dv, BitAction bit, uint8_t inIrq){
    
    GPIO_WriteBit(dv.sdaGpioPort, dv.sdaGpioPin, bit);
    
    if(inIrq){
        BSP_DelayUsInIrq(dv.sclWaitUs);
    }else{
        BSP_DelayUs(dv.sclWaitUs);
    }
    
    GPIO_WriteBit(dv.sclGpioPort, dv.sclGpioPin, Bit_SET);
    
    if(inIrq){
        BSP_DelayUsInIrq(dv.period - 2 * dv.sclWaitUs);
    }else{
        BSP_DelayUs(dv.period - 2 * dv.sclWaitUs);
    }
    
    GPIO_WriteBit(dv.sclGpioPort, dv.sclGpioPin, Bit_RESET);
    if(inIrq){
        BSP_DelayUsInIrq(dv.sclWaitUs);
    }else{
        BSP_DelayUs(dv.sclWaitUs);
    }
}

uint8_t BSP_SoftI2C_ReceiveBit(Device_SoftI2C dv, uint8_t inIrq){
    uint32_t queryTimes = dv.period / dv.queryPeriod, t;
    for(t = 0; t < queryTimes; t++){
        if(GPIO_ReadInputDataBit(dv.sclGpioPort, dv.sclGpioPin) != 0x00){
            if(GPIO_ReadInputDataBit(dv.sdaGpioPort, dv.sdaGpioPin) == 0x00){
                return 0x00;
            }else{
                return 1U;
            }
        }else{
            if(inIrq){
                BSP_DelayUsInIrq(dv.queryPeriod);
            }else{
                BSP_DelayUs(dv.queryPeriod);
            }
            continue;
        }
    }
    return 2U; // Timeout
}

void BSP_SoftI2C_Start(Device_SoftI2C dv, uint8_t inIrq){
        
    GPIO_WriteBit(dv.sdaGpioPort, dv.sdaGpioPin, Bit_SET);
    if(inIrq){
        BSP_DelayUsInIrq(dv.sclWaitUs);
    }else{
        BSP_DelayUs(dv.sclWaitUs);
    }
    
    
    if(inIrq){
        BSP_DelayUsInIrq(dv.period / 2 - dv.sclWaitUs);
    }else{
        BSP_DelayUs(dv.period / 2 - dv.sclWaitUs);
    }
    
    GPIO_WriteBit(dv.sdaGpioPort, dv.sdaGpioPin, Bit_RESET);
    
    if(inIrq){
        BSP_DelayUsInIrq(dv.period / 2);
    }else{
        BSP_DelayUs(dv.period / 2);
    }
}

void BSP_SoftI2C_End(Device_SoftI2C dv, uint8_t inIrq){
    
    GPIO_WriteBit(dv.sdaGpioPort, dv.sdaGpioPin, Bit_RESET);
    if(inIrq){
        BSP_DelayUsInIrq(dv.sclWaitUs);
    }else{
        BSP_DelayUs(dv.sclWaitUs);
    }
    
    
    if(inIrq){
        BSP_DelayUsInIrq(dv.period / 2 - dv.sclWaitUs);
    }else{
        BSP_DelayUs(dv.period / 2 - dv.sclWaitUs);
    }
    
    GPIO_WriteBit(dv.sdaGpioPort, dv.sdaGpioPin, Bit_SET);
    
    if(inIrq){
        BSP_DelayUsInIrq(dv.period / 2);
    }else{
        BSP_DelayUs(dv.period / 2);
    }
}

